package com.acme.bankapp;

import com.acme.bankapp.domain.Bank;
import com.acme.bankapp.domain.Client;
import com.acme.bankapp.domain.Gender;
import com.acme.bankapp.domain.account.Account;
import com.acme.bankapp.domain.account.CheckingAccount;
import com.acme.bankapp.domain.account.SavingAccount;
import com.acme.bankapp.exception.BankException;
import com.acme.bankapp.exception.IllegalAccountCreationException;
import com.acme.bankapp.service.BankService;

import java.io.*;

/**
 * Created by phashik on 21.11.2014.
 */
public class Connection {
    private InputStream inputStream;
    private OutputStream outputStream;
    private boolean sessionEnded = false;

    public Connection(InputStream inputStream, OutputStream outputStream) {
        this.inputStream = inputStream;
        this.outputStream = outputStream;
    }

    public void start(Bank bank) throws IOException {
        try(
                DataOutputStream out = new DataOutputStream(outputStream);
                DataInputStream in = new DataInputStream(inputStream)
        ) {
            String command;
            while (!sessionEnded) {
                command = in.readUTF();
                if ("exit".equals(command)) {
                    sessionEnded = true;
                }
                processRequest(bank, in, out, command);
            }
        }
    }

    private void processRequest(Bank bank, DataInputStream dis, DataOutputStream dos, String command) throws IOException {
        switch (command.toLowerCase()) {
            case "printbank":
                dos.writeInt(bank.getClients().length);
                for (Client client : bank.getClients()) {
                    dos.writeUTF(client.toString());
                }
                break;
            case "addnew":
                try {
                    registerNewClient(bank, dis, dos);
                    BankService.saveBank(bank, "bank.ser");
                } catch (BankException e) {
                    dos.writeInt(1);
                    dos.writeUTF("Client was not added. Too much clients already.");
                }
                break;
            case "exit":
                dos.writeInt(1);
                dos.writeUTF("Session ended. Server closes connection.");
                break;
            default:
                dos.writeInt(1);
                dos.writeUTF("Wrong command");
                break;
        }
    }

    private void registerNewClient(Bank bank, DataInputStream dis, DataOutputStream dos) throws IOException, BankException {
        String name = getName(dis, dos);
        Gender gender = getGender(dis, dos);
        Client client = new Client(name, gender);
        bank.addClient(client);

        client.addAccount(getAccount(dis, dos));
        dos.writeInt(1);
        dos.writeUTF("Client added.");
    }

    private Account getAccount(DataInputStream dis, DataOutputStream dos) throws IOException {
        Account account = null;
        dos.writeInt(1);
        dos.writeUTF("Enter account type (c/s):");
        String accType = dis.readUTF();

        getBalanceLoop:
        while (true) {
            try {
                dos.writeInt(1);
                dos.writeUTF("Enter start balance:");
                double balance = Double.parseDouble(dis.readUTF());
                switch (accType) {
                    case "s":
                        account = new SavingAccount(balance);
                        break getBalanceLoop;
                    case "c":
                        dos.writeInt(1);
                        dos.writeUTF("Enter overdraft:");
                        double overdraft = Double.parseDouble(dis.readUTF());
                        account = new CheckingAccount(balance, overdraft);
                        break getBalanceLoop;
                    default:
                        dos.writeInt(1);
                        dos.writeUTF("Account type not recognized. Try again. Press enter to continue.");
                        dis.readUTF();
                        return getAccount(dis, dos);
                }
            } catch (IllegalAccountCreationException e) {
                dos.writeInt(1);
                dos.writeUTF("Do not enter negative values. Try again. Press enter to continue.");
                dis.readUTF();
            }
        }
        return account;
    }

    private Gender getGender(DataInputStream dis, DataOutputStream dos) throws IOException {
        dos.writeInt(1);
        dos.writeUTF("Enter client's gender (m/f):");
        String g = dis.readUTF();
        Gender gender;
        switch (g) {
            case "m":
                gender = Gender.MALE;
                break;
            case "f":
                gender = Gender.FEMALE;
                break;
            default:
                dos.writeInt(1);
                dos.writeUTF("Account type not recognized. Try again. Press enter to continue.");
                dis.readUTF();
                return getGender(dis, dos);
        }
        return gender;
    }

    private String getName(DataInputStream dis, DataOutputStream dos) throws IOException {
        dos.writeInt(1);
        dos.writeUTF("Enter client's name:");
        return dis.readUTF();
    }

}
